package com.sojson.util.kd.kdn;

import com.sojson.constant.ConstantByMap;
import com.sojson.enums.core.EEnvironmentType;
import com.sojson.util.kd.kdn.bean.KdnParam;
import com.sojson.util.kd.kdn.bean.KdnResponse;
import com.sojson.util.kd.kdn.impl.KdnOfficialUtilImpl;
import com.sojson.util.kd.kdn.impl.KdnTestUtilImpl;

/**
 * 快递鸟工具类
 * 
 * @author liu
 * @date 2021-04-01
 */
public class KdnUtil {

    /** 实现类 */
    private static final KdnUtilInterface KDN_UTIL_INTERFACE = getKdnUtilInterface();

    /** ------------------------------R:必填----------------------------- */
    /** ------------------------------C:一定条件下可选--------------------- */
    /** ------------------------------O:可选----------------------------- */

    /**
     * 即时查询接口(此接口用于向快递公司实时查询物流轨迹信息)<BR/>
     * 1.主流快递仅支持申通快递、圆通速递、百世快递、天天快递 4家,不支持 EMS、邮政快递包裹、顺丰速运、韵达速递、京东快递、中通快递;
     * 如需查询所有主流快递公司,请选用在途监控服务;<BR/>
     * 2.并发不能超过 10次/S;<BR/>
     * 3.不能超过 500次/天;<BR/>
     * 
     * @param ShipperCode   R   快递公司编码
     * @param LogisticCode  R   快递单号
     * @param CustomerName  C   顺丰快递传(寄件人/收件人手机号后四位),京东快递传商家编码(由发货方提供,且快递单号必须是通过该商家编码下单获取的)(为其他快递时,可不填或保留字段,不可传值)
     * @param OrderCode     O   订单编号
     * @return 不会返回空
     * @throws Exception
     */
    public static KdnResponse timelyQuery(KdnParam kdnParam) throws Exception {
        return KDN_UTIL_INTERFACE.timelyQuery(kdnParam);
    }

    /**
     * 轨迹订阅接口(当物流有跟新的时候,会通知参数中的回调接口,直到运单签收)<BR/>
     * 1.主流快递仅支持申通快递、圆通速递、百世快递、天天快递 4家,不支持 EMS、邮政快递包裹、顺丰速运、韵达速递、京东快递、中通快递;
     * 如需查询所有主流快递公司,请选用在途监控服务;<BR/>
     * 2.接口对订阅的数据不做判断和校验,不校验快递公司编码和单号是否匹配,不判断快递单号是否合法、是否正确、是否重复订阅;<BR/>
     * 3.并发不能超过 30次/S;<BR/>
     * 4.不能超过 100单/天;<BR/>
     * 5.推送时效: 6至24小时内<BR/>
     * 
     * @param ShipperCode           R   快递公司编码
     * @param CustomerName          C   顺丰快递传(寄件人/收件人手机号后四位),京东快递传商家编码(由发货方提供,且快递单号必须是通过该商家编码下单获取的)(为其他快递时,可不填或保留字段,不可传值)
     * @param Receiver.PostCode     C   收件地邮编(ShipperCode为 EMS、YZPY、YZBK 时必填)
     * @param Sender.PostCode       C   发件地邮编(ShipperCode为 EMS、YZPY、YZBK 时必填)
     * @param LogisticCode          R   快递单号
     * @param Receiver.Name         R   收件人
     * @param Receiver.Tel          R   电话(电话与手机,必填一个)
     * @param Receiver.Mobile       R   手机(电话与手机,必填一个)
     * @param Receiver.ProvinceName R   收件省(如广东省,不要缺少“省”;如是直辖市,请直接传北京、上海等;如是自治区,请直接传广西壮族自治区等)
     * @param Receiver.CityName     R   收件市(如深圳市,不要缺少“市;如是市辖区,请直接传北京市、上海市等”)
     * @param Receiver.ExpAreaName  R   收件区/县(如福田区,不要缺少“区”或“县”)
     * @param Receiver.Address      R   收件人详细地址(不用传省市区)
     * @param Sender.Name           R   发件人
     * @param Sender.Tel            R   电话(电话与手机,必填一个)
     * @param Sender.Mobile         R   手机(电话与手机,必填一个)
     * @param Sender.ProvinceName   R   发件省(如广东省,不要缺少“省”;如是直辖市,请直接传北京、上海等;如是自治区,请直接传广西壮族自治区等)
     * @param Sender.CityName       R   发件市(如深圳市,不要缺少“市;如是市辖区,请直接传北京市、上海市等”)
     * @param Sender.ExpAreaName    R   发件区/县(如福田区,不要缺少“区”或“县”)
     * @param Sender.Address        R   发件人详细地址(不用传省市区)
     * @return 不会返回空
     * @throws Exception
     */
    public static KdnResponse trackSubscription(KdnParam kdnParam) throws Exception {
        return KDN_UTIL_INTERFACE.trackSubscription(kdnParam);
    }

    /**
     * 单号识别接口<BR/>
     * 1.接口只对快递单号进行识别,返回可能属于的一家或多家快递公司,可能性最高的排名靠前,实际归属哪家快递公司仍需用户判断;<BR/>
     * 2.识别失败,接口返回为空;<BR/>
     * 3.快递公司新上线的号段首次会识别失败;进行轨迹订阅并拉取到轨迹后,单号识别接口学习机制会完善此类单号的识别;<BR/>
     * 4.不能超过 30000 次/天<BR/>
     * 
     * @param LogisticCode  R   快递单号
     * @param kdnParam
     * @return 不会返回空
     * @throws Exception
     */
    public static KdnResponse orderNoDiscern(KdnParam kdnParam) throws Exception {
        return KDN_UTIL_INTERFACE.orderNoDiscern(kdnParam);
    }

    /**
     * 单号校验接口(如果单号识别不了,或者不是所选快递的就抛异常)<BR/>
     * 
     * @param ShipperCode   R   快递公司编码
     * @param LogisticCode  R   快递单号
     * @param kdnParam
     * @throws Exception 
     */
    public static void orderNoVerify(KdnParam kdnParam) throws Exception {
        KDN_UTIL_INTERFACE.orderNoVerify(kdnParam);
    }

    /**
     * 获取实现类
     * 
     * @return
     */
    private static final KdnUtilInterface getKdnUtilInterface() {
        if (ConstantByMap.ENVIRONMENT == EEnvironmentType.TEST.getCode()) {
            return KdnTestUtilImpl.getInstances();
        } else if (ConstantByMap.ENVIRONMENT == EEnvironmentType.ONLINE.getCode()) {
            return KdnOfficialUtilImpl.getInstances();
        }

        return KdnTestUtilImpl.getInstances();
    }

}